package com.system.ad.mysql.dto;

import com.system.ad.mysql.constant.OpType;
import lombok.Data;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

/**
 * 模板文件解析类，用于解析模板文件信息并生成模板对象
 */
@Data
public class ParseTemplate {
    // 数据库名称
    private String database;

    // 表名与表格模板的映射关系
    private Map<String, TableTemplate> tableTemplateMap = new HashMap<>();

    /**
     * 解析模板文件，生成模板对象
     *
     * @param _template 待解析的模板文件对象
     * @return 解析后的模板对象
     */
    public static ParseTemplate parse(Template _template) {
        ParseTemplate parseTemplate = new ParseTemplate();
        parseTemplate.setDatabase(_template.getDatabase());

        // 遍历模板文件中的每个表格信息
        for (JsonTable table : _template.getTableList()) {
            String tableName = table.getTableName(); // 表名
            Integer level = table.getLevel(); // 表层级

            TableTemplate tableTemplate = new TableTemplate();
            tableTemplate.setTableName(tableName);
            tableTemplate.setLevel(level.toString());

            parseTemplate.getTableTemplateMap().put(tableName, tableTemplate);

            // 获取操作类型对应的列集合映射
            Map<OpType, List<String>> opTypeListMap = tableTemplate.getOpTypeFieldSetMap();

            // 遍历插入操作的列，并添加到对应操作类型的列集合中
            for (JsonTable.Column column : table.getInsert()) {
                getAndCreateIfNeed(OpType.ADD, opTypeListMap, ArrayList::new).add(column.getColumn());
            }

            // 遍历更新操作的列，并添加到对应操作类型的列集合中
            for (JsonTable.Column column : table.getUpdate()) {
                getAndCreateIfNeed(OpType.UPDATE, opTypeListMap, ArrayList::new).add(column.getColumn());
            }

            // 遍历删除操作的列，并添加到对应操作类型的列集合中
            for (JsonTable.Column column : table.getDelete()) {
                getAndCreateIfNeed(OpType.DELETE, opTypeListMap, ArrayList::new).add(column.getColumn());
            }
        }
        return parseTemplate;
    }

    /**
     * 获取操作类型对应的集合，并在需要时创建新集合
     *
     * @param key     操作类型
     * @param map     操作类型与集合的映射关系
     * @param factory 创建新集合的工厂方法
     * @param <T>     操作类型泛型
     * @param <R>     集合泛型
     * @return 操作类型对应的集合
     */
    private static <T, R> R getAndCreateIfNeed(T key, Map<T, R> map, Supplier<R> factory) {
        return map.computeIfAbsent(key, k -> factory.get());
    }

}
